﻿
using DetectingKinectSencor.Tools;
using System.Data.SQLite;
using Microsoft.Kinect;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using DetectingKinectSencor._40_Tools;


namespace DetectingKinectSencor.BodyLanguage
{
    class GesturesManager
    {
        private Skeleton skeleton;

        private Stopwatch counterTillOpenGesturesDetection;
        private Stopwatch counterTillHandsBelowWaistLineDetection;

        private Vector3 leftHandPosition;
        private Vector3 rightHandPosition;
        private Vector3 leftHipPosition;
        private Vector3 leftShoulderPosition;
        private Vector3 rightShoulderPosition;
        private int openGestureID;
        private int handsBelowWaistLineID;
        private bool openGestureDetected;

        private bool handsBelowWaistLineDetected;
        private SQLiteConnection databaseConnection;
        private SQLiteCommand sqliteCommandOpenGestures;
        private SQLiteCommand sqliteCommandBelowWaistline;
        public DateTime startedCaptureTime;
        private DateTime openGestureDetectedTimePoint;
        private DateTime handsBelowWaistLineDetectedTimePoint;

        private TimeSpan timeSpanHandsBelowWaistline;

        private float actualRightShoulderPositon;
        private float actualLeftShoulderPostion;
        private float differenceRightLeftShoulder;
        private float differenceLeftRightShoulder;
        private float actualLeftHip;
        private bool positionSet;


        public GesturesManager(SQLiteConnection databaseConnection)
        {


            this.databaseConnection = databaseConnection;

            // create a new SQL command:
            sqliteCommandOpenGestures = databaseConnection.CreateCommand();
            sqliteCommandBelowWaistline = databaseConnection.CreateCommand();

            openGestureID = 0;
            handsBelowWaistLineID = 0;

            counterTillOpenGesturesDetection = new Stopwatch();
            counterTillHandsBelowWaistLineDetection = new Stopwatch();
        }


        internal void doWork(object skeleton)
        {
            this.skeleton = (Skeleton)skeleton;

            leftHandPosition = Vector3.ToVector3(this.skeleton.Joints.Where(j => j.JointType ==
            JointType.HandLeft).First().Position);

            rightHandPosition = Vector3.ToVector3(this.skeleton.Joints.Where(j => j.JointType ==
            JointType.HandRight).First().Position);

            leftHipPosition = Vector3.ToVector3(this.skeleton.Joints.Where(j => j.JointType ==
            JointType.HipLeft).First().Position);

            leftHipPosition = Vector3.ToVector3(this.skeleton.Joints.Where(j => j.JointType ==
            JointType.HipLeft).First().Position);

            leftShoulderPosition = Vector3.ToVector3(this.skeleton.Joints.Where(j => j.JointType ==
            JointType.ShoulderLeft).First().Position);

            rightShoulderPosition = Vector3.ToVector3(this.skeleton.Joints.Where(j => j.JointType ==
            JointType.ShoulderRight).First().Position);


            // Left shoulder nearer
            differenceRightLeftShoulder = rightShoulderPosition.Z - leftShoulderPosition.Z;

            // right shoulder nearer
            differenceLeftRightShoulder = leftShoulderPosition.Z - rightShoulderPosition.Z;



            // left shoulder is nearer
            if (differenceRightLeftShoulder > XMLproperties.thresholdToCalculateOffestForNewShoulderPosition)
            {
                actualRightShoulderPositon = rightShoulderPosition.X + XMLproperties.offsetOpenGesture + XMLproperties.additionalOffsetSmall;
                actualLeftShoulderPostion = leftShoulderPosition.X - XMLproperties.offsetOpenGesture + XMLproperties.additionalOffsetBig;
                positionSet = true;
            }
            else
            {
                // right shoulder nearrer
                if (differenceLeftRightShoulder > XMLproperties.thresholdToCalculateOffestForNewShoulderPosition)
                {
                    actualRightShoulderPositon = rightShoulderPosition.X + XMLproperties.offsetOpenGesture - XMLproperties.additionalOffsetBig;
                    actualLeftShoulderPostion = leftShoulderPosition.X - XMLproperties.offsetOpenGesture - XMLproperties.additionalOffsetSmall;
                    positionSet = true;
                }
            }


            // If there is no rotation in the Y-axes then add the normal offset
            if(!positionSet)            
            {
                actualRightShoulderPositon = rightShoulderPosition.X + XMLproperties.offsetOpenGesture;
                actualLeftShoulderPostion = leftShoulderPosition.X - XMLproperties.offsetOpenGesture;
            }



            // Set actual hip position
            actualLeftHip = leftHipPosition.Y - XMLproperties.offsetHandsBelowWaistline;


            // Detect open gesture, but only if the hands are above the wasteline
            if (((actualRightShoulderPositon < rightHandPosition.X) || (actualLeftShoulderPostion > leftHandPosition.X))
                && !((actualLeftHip > leftHandPosition.Y) || (actualLeftHip > rightHandPosition.Y)))
            {
                if (counterTillOpenGesturesDetection.IsRunning)
                {
                     if (counterTillOpenGesturesDetection.Elapsed.Milliseconds > XMLproperties.milliSecondsTillOpenGestureDetected)
                    {
                        openGestureDetected = true;
                    }
                }
                else
                {
                    openGestureDetectedTimePoint = DateTime.Now;
                    counterTillOpenGesturesDetection.Start();
                }
            }
            else
            {
                if (openGestureDetected)
                {
                    try{
                        openGestureID++;

                        // Saved the detection into the sqlite DB
                        // The timespanMinute and seconds are null, because here we do not need them at the moment
                        sqliteCommandOpenGestures.CommandText =
                            "INSERT INTO open_gestures (capturedTime, timepoint, timespanMinute, timespanSec) VALUES ('" + startedCaptureTime + "', '"
                                                                                                                         + openGestureDetectedTimePoint + "', "
                                                                                                                         + 0 + ","
                                                                                                                         + 0 + ");";
                        sqliteCommandOpenGestures.ExecuteNonQuery();

                        Console.WriteLine("Open gesture detected after: " + openGestureID);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    openGestureDetected = false;
                }

                if(counterTillOpenGesturesDetection.IsRunning)
                    counterTillOpenGesturesDetection.Reset();
            }



            // Arms below or above wasteline
            if ((actualLeftHip > leftHandPosition.Y) || (actualLeftHip > rightHandPosition.Y))
            {
                // Check if the counter has been started or not
                if (counterTillHandsBelowWaistLineDetection.IsRunning)
                {
                    // Start to detect if the hands are more than a half second below the wasteline
                    if (counterTillHandsBelowWaistLineDetection.Elapsed.Seconds > XMLproperties.secondsTillHandsBelowwastelineDetected)
                    {
                        // Hands are below the wasteline longer than a half second, so detected to true
                        handsBelowWaistLineDetected = true;
                    }
                }
                else
                {
                    handsBelowWaistLineDetectedTimePoint = DateTime.Now;

                    // Counter has not been started yet
                    counterTillHandsBelowWaistLineDetection.Start();
                }
            }
            else
            {
                // if hands below the wastline were detected
                if (handsBelowWaistLineDetected)
                {
                    try
                    {
                        timeSpanHandsBelowWaistline = DateTime.Now - handsBelowWaistLineDetectedTimePoint;

                        handsBelowWaistLineID++;

                        // Saved the detection into the sqlite DB
                        // The timespanMinute and seconds are null, because here we do not need them at the moment
                        sqliteCommandBelowWaistline.CommandText =
                            "INSERT INTO hands_below_wasteline (capturedTime, timepoint, timespanMinute, timespanSec) VALUES ('" + startedCaptureTime + "', '"
                                                                                                                                 + handsBelowWaistLineDetectedTimePoint + "', "
                                                                                                                                 + timeSpanHandsBelowWaistline.Minutes + ","
                                                                                                                                 + timeSpanHandsBelowWaistline.Seconds
                                                                                                                                 + ");";
                        sqliteCommandBelowWaistline.ExecuteNonQuery();

                        Console.WriteLine("Hands are below wasteline: " + handsBelowWaistLineID
                                                                        + " minutes: "
                                                                        + timeSpanHandsBelowWaistline.Minutes
                                                                        + " seconds: "
                                                                        + timeSpanHandsBelowWaistline.Seconds);
                    }

                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }

                    handsBelowWaistLineDetected = false;
                }
                
                if(counterTillHandsBelowWaistLineDetection.IsRunning)
                    counterTillHandsBelowWaistLineDetection.Reset();
            }
            positionSet = false;
        }
    }
}
